package handler

import (
	"net/http"
	"strconv"
	"time"
	"yunpan/app"
	"yunpan/db"
	"yunpan/logger"
	"yunpan/pool"
	"yunpan/store/ceph"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// 获取回收站文件列表
func GetTrashList(c *gin.Context, dbPool *pool.DBWorkerPool) {
	username := c.MustGet("username").(string)
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "20"))

	// 创建数据库任务
	var files []db.UserFile
	var total int64

	dbTask := pool.NewDBTask(
		"获取回收站列表",
		3,
		func() error {
			var err error
			files, total, err = db.GetUserTrashList(username, page, pageSize)
			return err
		},
	)

	// 提交任务到线程池
	if err := dbPool.Submit(dbTask); err != nil {
		logger.Error("提交获取回收站列表任务失败",
			zap.String("username", username),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "提交任务失败: " + err.Error(),
		})
		return
	}

	// 等待任务完成
	if err := dbTask.Wait(); err != nil {
		logger.Error("获取回收站列表失败",
			zap.String("username", username),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "获取回收站列表失败: " + err.Error(),
		})
		return
	}

	var fileList []gin.H
	for _, file := range files {
		retentionDays := 10 - int(time.Since(*file.DeletedAt).Hours()/24)
		if retentionDays < 0 {
			retentionDays = 0
		}

		fileList = append(fileList, gin.H{
			"id":            file.FileHash,
			"name":          file.FileName,
			"size":          file.FileSize,
			"type":          getFileType(file.FileName, file.IsFolder),
			"isFolder":      file.IsFolder,
			"path":          file.ParentPath + file.FileName,
			"deletedAt":     file.DeletedAt.Format("2006-01-02 15:04:05"),
			"retentionDays": retentionDays,
		})
	}
	logger.Info("获取回收站列表成功",
		zap.String("username", username),
		zap.Int("fileCount", len(fileList)),
		zap.Int64("total", total))

	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"data": gin.H{
			"files":    fileList,
			"total":    total,
			"page":     page,
			"pageSize": pageSize,
			"isTrash":  true,
		},
	})
}

// 恢复文件
func RestoreFile(c *gin.Context) {
	username := c.MustGet("username").(string)
	var req struct {
		FileID string `json:"fileSha1"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": 400,
			"msg":  "参数错误",
		})
		return
	}

	if err := db.RestoreUserFile(username, req.FileID); err != nil {
		logger.Error("恢复文件失败",
			zap.String("username", username),
			zap.String("fileID", req.FileID),
			zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "恢复文件失败: " + err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "恢复成功",
	})
}

// 彻底删除文件
func PermanentlyDeleteFile(c *gin.Context) {
    username := c.MustGet("username").(string)
    var req struct {
        FileSha1 string `json:"fileSha1"`
		FileName string `json:"FileName"`
    }

    if err := c.ShouldBindJSON(&req); err != nil {
        logger.Error("参数错误",
            zap.String("username", username),
            zap.Error(err))
        c.JSON(http.StatusBadRequest, gin.H{
            "code": 400,
            "msg":  "参数错误",
        })
        return
    }

    ctx := app.GetContext()
    dbPool := ctx.DBPool
    cephPool := ctx.CephPool

    type fileResult struct {
        file *db.UserFile
        err  error
    }

    result := make(chan fileResult, 1)

    // 获取文件信息
    var file *db.UserFile
    // var getFileErr error

    dbTask := pool.NewDBTask(
        "获取文件信息",
        3,
        func() error {
            f, err := db.GetUserFile(username, req.FileSha1)
            result <- fileResult{file: f, err: err}
            return err
        },
    )

    if err := dbPool.Submit(dbTask); err != nil {
        logger.Error("提交获取文件信息任务失败",
            zap.String("username", username),
            zap.String("fileID", req.FileSha1),
            zap.Error(err))
        c.JSON(http.StatusInternalServerError, gin.H{
            "code": 500,
            "msg":  "提交任务失败: " + err.Error(),
        })
        return
    }

    // 等待获取文件信息的结果
    taskResult := <-result
    if taskResult.err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "code": 500,
            "msg":  "获取文件信息失败: " + taskResult.err.Error(),
        })
        return
    }
    file = taskResult.file

    var cephTask pool.Task
    if file.IsOriginal && file.ReferenceCount == 1 {
        // 只有在需要删除实际文件时才创建 Ceph 任务
        fullPath := file.ParentPath + file.FileName
        if file.IsFolder {
            fullPath += "/"
        }
        if fullPath[0] == '/' {
            fullPath = fullPath[1:]
        }

        cephTask = pool.NewCephTask(
            username,
            "删除文件",
            3,
            func(conn *ceph.StorageSession) error {
                return conn.DeleteObject(fullPath)
            },
        )

        if err := cephPool.Submit(cephTask); err != nil {
            logger.Error("提交存储删除任务失败",
                zap.String("username", username),
                zap.String("fileID", req.FileSha1),
                zap.String("path", fullPath),
                zap.Error(err))
            c.JSON(http.StatusInternalServerError, gin.H{
                "code": 500,
                "msg":  "提交删除任务失败: " + err.Error(),
            })
            return
        }
    }

    // 创建数据库删除任务
    dbDeleteResult := make(chan error, 1)
    dbDeleteTask := pool.NewDBTask(
        "删除文件记录",
        3,
        func() error {
            var err error
            if !file.IsOriginal {
                // 快捷方式：删除当前记录并减少源文件引用计数
                uFile,err := db.DeleteShortcut(req.FileName, req.FileSha1)
				if err != nil{
					return err
				}
				deleteSource(uFile)
            } else if file.ReferenceCount == 1 {
                // 引用计数为1：删除文件和数据库记录
                err = db.PermanentlyDeleteUserFile(username, req.FileSha1)
            } else {
                // 引用计数大于1：仅减少引用计数并保留源文件记录
                err = db.DecrementReferenceAndUpdateStatus(username, req.FileSha1)
            }
            dbDeleteResult <- err
            return err
        },
    )

    if err := dbPool.Submit(dbDeleteTask); err != nil {
        logger.Error("提交数据库删除任务失败",
            zap.String("username", username),
            zap.String("fileID", req.FileSha1),
            zap.Error(err))
        c.JSON(http.StatusInternalServerError, gin.H{
            "code": 500,
            "msg":  "提交删除任务失败: " + err.Error(),
        })
        return
    }

    // 等待所有任务完成
    if cephTask != nil {
        if err := waitForTasks(cephTask); err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{
                "code": 500,
                "msg":  "从存储中删除文件失败: " + err.Error(),
            })
            return
        }
    }

    // 等待数据库删除结果
    if err := <-dbDeleteResult; err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "code": 500,
            "msg":  "删除文件失败: " + err.Error(),
        })
        return
    }

    logger.Info("文件删除成功",
        zap.String("username", username),
        zap.String("fileID", req.FileSha1))
    c.JSON(http.StatusOK, gin.H{
        "code": 200,
        "msg":  "删除成功",
    })
}


func deleteSource(uFile *db.UserFile){
	if uFile.ReferenceCount < 1{
		ceph, err := ceph.GetCephConn(uFile.UserName)
		if err != nil {
			logger.Error("获取Ceph连接失败",
				zap.String("username", uFile.UserName),
				zap.Error(err),
			)
			return 
		}
		uFullPath := uFile.ParentPath + uFile.FileName
		if uFile.IsFolder {
			uFullPath += "/"
		}
		if uFullPath[0] == '/' {
			uFullPath = uFullPath[1:]
		}
		ceph.DeleteObject(uFullPath)
		db.PermanentlyDeleteUserFile(uFile.UserName,uFile.FileHash)
	}
}